package com.devops.shiro.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.devops.admin.model.IntrospectResponse;
import com.devops.admin.po.DOSBaseUserPo;
import com.devops.admin.po.DOSRolePo;
import com.devops.common.utils.PasswordUtil;
import com.devops.common.utils.SpringUtil;
import com.devops.constant.DOSRoleEnum;
import com.devops.constant.DevOpsConstant;
import com.devops.shiro.service.DOSBaseUserService;
import com.devops.shiro.util.EntityUtils;
import com.devops.shiro.vm.BaseUserCreateVM;
import com.devops.shiro.vm.BaseUserVM;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class KeycloakShiroRealm extends AuthorizingRealm {

    public boolean supports(AuthenticationToken token) {
        return token instanceof KeycloakAuthenticationToken; // 确认Token类型
    }

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
      throws AuthenticationException {
      // 使用Keycloak的令牌来验证用户的身份
      KeycloakAuthenticationToken keycloakToken = (KeycloakAuthenticationToken) authcToken;
      String idToken = keycloakToken.getCredentials().toString();

      String keycloakServerUrl = SpringUtil.getProperty("keycloak.auth-server-url").toString();
      String keycloakRealm = SpringUtil.getProperty("keycloak.realm").toString();
      String clientId = SpringUtil.getProperty("keycloak.resource").toString();
      String clientSecret = SpringUtil.getProperty("keycloak.credentials.secret").toString();

      Map<String, Object> params = new HashMap<>();
      params.put("client_id", clientId);
      params.put("client_secret", clientSecret);
      params.put("token", idToken);
      HttpResponse response = HttpUtil.createPost(StrUtil.format("{}/realms/{}/protocol/openid-connect/token/introspect",
                      keycloakServerUrl, keycloakRealm))
              .form(params)
              .timeout(6000)
              .execute();
      if (200 != response.getStatus()) {
          throw new AuthenticationException("token无效");
      }
      IntrospectResponse introspectResponse = JSONUtil.toBean(response.body(), IntrospectResponse.class);

      DOSBaseUserService dosBaseUserService = (DOSBaseUserService) SpringUtil.getBean("dosBaseUserServiceImpl");
      DOSBaseUserPo userPo = dosBaseUserService.getBaseUserByLoginName(introspectResponse.getUsername());
      if(userPo == null){
          BaseUserCreateVM userCreateVo = BaseUserCreateVM.builder()
                  .loginName(introspectResponse.getUsername())
                  .realName(introspectResponse.getFamilyName()+introspectResponse.getGivenName())
                  .nickName(introspectResponse.getFamilyName()+introspectResponse.getGivenName())
                  .sex(true)
                  .email(introspectResponse.getEmail())
                  .password(PasswordUtil.generatePassword())
                  .roleIds(new ArrayList<>())
                  .build();
          dosBaseUserService.addUser(userCreateVo);
          userPo = dosBaseUserService.getBaseUserByLoginName(introspectResponse.getUsername());
      }

      BaseUserVM baseUserVM = EntityUtils.entity2VM(userPo, BaseUserVM.class, "");
      //超管 普管 QA 都赋予管理角色
      List<String> roleCodes = baseUserVM.getRoles().stream().map(DOSRolePo::getRoleCode).collect(Collectors.toList());

      baseUserVM.setAdminRole(roleCodes.contains(DOSRoleEnum.SUPER_ADMINISTRATOR.getRoleCode())
              || roleCodes.contains(DOSRoleEnum.ADMINISTRATOR.getRoleCode())
              || roleCodes.contains(DOSRoleEnum.QA_ADMINISTRATOR.getRoleCode()));
      baseUserVM.setIdToken(idToken);
      return new SimpleAuthenticationInfo(baseUserVM, idToken, this.getName());
  }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
        //菜单级别的权限 由数据库控制
        //接口级别的权限控制 用 @RequiresPermissions()
        //数据级别的权限控制 用baseUserVM.getAdminRole 管理角色可看到所有的数据
        BaseUserVM baseUserVM = EntityUtils.entity2VM(principals.getPrimaryPrincipal(),BaseUserVM.class);
        List<String> roleCodes = baseUserVM.getRoles().stream().map(DOSRolePo::getRoleCode).collect(Collectors.toList());
        if (baseUserVM.getId() != null) {
            simpleAuthorInfo.addStringPermission(DevOpsConstant.RoleCode.LOGIN_USER);
            simpleAuthorInfo.addStringPermissions(roleCodes);
        }
        return simpleAuthorInfo;
    }
}